using UnityEngine;
using UnityEditor;
using Prota.Editor;
using System;
using System.Collections.Generic;

namespace Prota.Editor
{
    public abstract class UpdateOnPrefChangeEntry
    {
        public readonly string key;
        
        public UpdateOnPrefChangeEntry(string key)
        {
            this.key = key;
        }
    }
    
    public class EditorPrefEntryInt : UpdateOnPrefChangeEntry
    {
        public readonly int defaultValue = default;
        
        public int value
        {
            get => EditorPrefs.GetInt(key, defaultValue);
            set => EditorPrefs.SetInt(key, value);
        }
        
        public EditorPrefEntryInt(string key, int defaultValue = default) : base(key)
        {
            this.defaultValue = defaultValue;
        }
    }
    
    public class EditorPrefEntryFloat : UpdateOnPrefChangeEntry
    {
        public readonly float defaultValue = default;
        
        public float value
        {
            get => EditorPrefs.GetFloat(key, defaultValue);
            set => EditorPrefs.SetFloat(key, value);
        }
        
        public EditorPrefEntryFloat(string key, float defaultValue = default) : base(key)
        {
            this.defaultValue = defaultValue;
        }
    }
    
    public class EditorPrefEntryString : UpdateOnPrefChangeEntry
    {
        public readonly string defaultValue = default;
        
        public string value
        {
            get => EditorPrefs.GetString(key, defaultValue);
            set => EditorPrefs.SetString(key, value);
        }
        
        public EditorPrefEntryString(string key, string defaultValue = default) : base(key)
        {
            this.defaultValue = defaultValue;
        }
    }
    
    public class EditorPrefEntryString<T> : UpdateOnPrefChangeEntry
    {
        public Func<string, T> getter;
        public Func<T, string> setter;
        
        readonly string defaultValue = default;
        
        public string rawValue
        {
            get => EditorPrefs.GetString(key, defaultValue);
            set => EditorPrefs.SetString(key, value);
        }
        
        public T value
        {
            get => getter(rawValue);
            set => setter(value);
        }
        
        public EditorPrefEntryString(string key, Func<string, T> getter, Func<T, string> setter, string defaultValue = default) : base(key)
        {
            this.getter = getter;
            this.setter = setter;
        }
    }
    
    public class EditorPrefEntryVec : UpdateOnPrefChangeEntry
    {
        public readonly string keyX;
        public readonly string keyY;
        public readonly string keyZ;
        public readonly string keyW;
        
        public Vector4 defaultValue = default;
        
        public Color color
        {
            get
            {
                return new Color(
                    EditorPrefs.GetFloat(keyX, defaultValue.x),
                    EditorPrefs.GetFloat(keyY, defaultValue.y),
                    EditorPrefs.GetFloat(keyZ, defaultValue.z),
                    EditorPrefs.GetFloat(keyW, defaultValue.w)
                );
            }
            set
            {
                EditorPrefs.SetFloat(keyX, value.r);
                EditorPrefs.SetFloat(keyY, value.g);
                EditorPrefs.SetFloat(keyZ, value.b);
                EditorPrefs.SetFloat(keyW, value.a);
            }
        }
        
        public Vector4 vec4
        {
            get
            {
                return new Vector4(
                    EditorPrefs.GetFloat(keyX, defaultValue.x),
                    EditorPrefs.GetFloat(keyY, defaultValue.y),
                    EditorPrefs.GetFloat(keyZ, defaultValue.z),
                    EditorPrefs.GetFloat(keyW, defaultValue.w)
                );
            }
            set
            {
                EditorPrefs.SetFloat(keyX, value.x);
                EditorPrefs.SetFloat(keyY, value.y);
                EditorPrefs.SetFloat(keyZ, value.z);
                EditorPrefs.SetFloat(keyW, value.w);
            }
        }
        
        public Vector3 vec3
        {
            get
            {
                return new Vector3(
                    EditorPrefs.GetFloat(keyX, defaultValue.x),
                    EditorPrefs.GetFloat(keyY, defaultValue.y),
                    EditorPrefs.GetFloat(keyZ, defaultValue.z)
                );
            }
            set
            {
                EditorPrefs.SetFloat(keyX, value.x);
                EditorPrefs.SetFloat(keyY, value.y);
                EditorPrefs.SetFloat(keyZ, value.z);
            }
        }
        
        public Vector2 vec2
        {
            get
            {
                return new Vector2(
                    EditorPrefs.GetFloat(keyX, defaultValue.x),
                    EditorPrefs.GetFloat(keyY, defaultValue.y)
                );
            }
            set
            {
                EditorPrefs.SetFloat(keyX, value.x);
                EditorPrefs.SetFloat(keyY, value.y);
            }
        }
        
        public EditorPrefEntryVec(string key, Vector4 defaultValue = default) : base(key)
        {
            this.keyX = key + "_x";
            this.keyY = key + "_y";
            this.keyZ = key + "_z";
            this.keyW = key + "_w";
            this.defaultValue = defaultValue;
        }
    }
    
    public class EditorPrefEntryBool : UpdateOnPrefChangeEntry
    {
        public readonly bool defaultValue = default;
        
        public bool value
        {
            get => EditorPrefs.GetBool(key, defaultValue);
            set => EditorPrefs.SetBool(key, value);
        }
        
        public EditorPrefEntryBool(string key, bool defaultValue = default) : base(key)
        {
            this.defaultValue = defaultValue;
        }
    }
    
}
